package org.lisanhu.easy2json;

import org.json.JSONArray;
import org.json.JSONObject;

import java.lang.annotation.*;
import java.lang.reflect.*;
import java.util.ArrayList;

public class Utils {

    public static JSONArray toJsonArray(Object val){

        if (val instanceof int[]
                ||  val instanceof double[]
                ||  val instanceof char[]
                ||  val instanceof float[]
                ||  val instanceof short[]
                ||  val instanceof long[]
                ||  val instanceof byte[]
                ||  val instanceof boolean[]
                ){
            return new JSONArray(val);
        }

        Object[] array = (Object[]) val;
        JSONArray a = new JSONArray();
        for (Object e : array) {

            if (e instanceof String
                    ||  e instanceof Number
                    ||  e instanceof JSONObject
                    ||  e instanceof JSONArray
                    ) {
                a.put(e);
            } else {
                a.put(toJson(e));
            }
        }
        return a;
    }

    public static JSONObject toJson(Object e) {
        Class<?> obj = e.getClass();
        JSONObject json = new JSONObject();
        Field[] fields = getMarkedFields(obj);

        for (Field f : fields) {
            String name = f.getName();
            f.setAccessible(true);
            try {
                Object val = f.get(e);
                if (hasTypeAnnotation(val)) {
                    val = toJson(val);
                }

                if (hasArrayAnnotation(f)) {
                    val = toJsonArray(val);
                }

                json.put(name, val);

            } catch (IllegalAccessException e1) {
                e1.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
            }
        }

        return json;
    }

    private static Field[] getMarkedFields(Class<?> obj) {
        Field[] fields = obj.getDeclaredFields();
        ArrayList<Field> fs = new ArrayList<>();
        for (Field f : fields) {
            if (hasFieldAnnotation(f) || hasArrayAnnotation(f)) {
                fs.add(f);
            }
        }
        fields = new Field[fs.size()];
        fields = fs.toArray(fields);
        return fields;
    }

    private static Boolean hasArrayAnnotation(Field f) {
        Annotation a = f.getAnnotation(ToJsonArray.class);
        return a != null;
    }

    private static Boolean hasFieldAnnotation(Field f) {
        Annotation a = f.getAnnotation(ToJsonField.class);
        return a != null;
    }

    private static Boolean hasTypeAnnotation(Object e) {
        Class<?> obj = e.getClass();
        Annotation a = obj.getAnnotation(ToJson.class);
        return a != null;
    }
}
